/*
 * \file XmlDirectory.cpp
 *
 * \date Created on: Jan 25, 2009
 * \author sarah
 */

#include <QSettings>
#include <QDebug>

#include "XmlDirectory.h"
#include "XmlException.h"
#include "XmlFileNotFound.h"

/*!
   \class XmlDirectory
   \brief Encapsulate query and setting of the Xml data directories.
   \details This class holds methods for querying the Xml data directory
   heierarchy, including the root directory.
 */

/*!
 * Directory name string for the storage of character data.
 */
const char *XmlDirectory::CHAR_DIR_NAME = "Characters";

/*!
 * \brief Construct a new XmlDirectory object.
 * \details Initialize the internal QDir object modelling the data root, using
 * the current definition from the QSettings.
 * \throw XmlException() if the data root is not defined, or XmlFileNotFound()
 * exception if the data root is defined but does not exist on the file system.
 */
XmlDirectory::XmlDirectory()
{
    QSettings settings;
    QString dataRoot = settings.value("paths/dataroot", QString()).toString();
    if (dataRoot.isEmpty())
        throw XmlException(QObject::tr("Dataroot not defined"));

    QDir rootDir(dataRoot);

    // This directory is created in the MainWindow startup
    if (!rootDir.exists())
        throw XmlFileNotFound(dataRoot);
    mRootDir = rootDir;
}

/*!
 * \brief Destroy the object, releasing any resources.
 */
XmlDirectory::~XmlDirectory()
{
}

/*!
 * \brief Determine the directory for the root of Xml data storage.
 * \details Calculate and return a QDir object of this root directory, below
 * which all Xml data is stored.  Internally this is set via a QSettings
 * object, configurable via the Preferences dialog.  However never use the
 * QSetting accessor directly, since the authoritative value of the QSettings
 * key is encoded in this class, and it may change.
 *
 * If the root directory does not exist, this method will \b not try to create
 * it.  Generally the application should ensure this directory exists at
 * application startup.
 *
 * \return QDir value of the Xml data root directory.
 */
QDir XmlDirectory::dataRootDir() const
{
    return mRootDir;
}

/*!
    \brief Set the directory for the root of all Xml data storage.
    \details Stores the resulting path to local settings.

    Any directories required that do not exist are made.

    The required directories are the root directory itself, and its "Class",
    "Race", "Feat", "Skill", "Equipment" and "Character" sub-directories.
 */
void XmlDirectory::setDataRootDir(const QDir &newDir)
{
    QSettings settings;
    settings.setValue("paths/dataroot", newDir.absolutePath());
    // qDebug() << "setDataRootDir" << newDir.absolutePath();
    if (!newDir.exists())
        if (!QDir::root().mkpath(newDir.absolutePath()))
            throw XmlException(QObject::tr("Could not create directory %1").arg(
                    newDir.absolutePath()));
    Q_ASSERT(newDir.exists());
    for ( int i = 0; i < XmlPath::NUM_BASE_TYPES; ++i )
    {
        QString typeName = XmlPath::BASE_TYPE_NAMES[i];
        QDir typeDir(newDir.absoluteFilePath(typeName));
        if (!typeDir.exists())
            if (!newDir.mkdir(typeName))
                throw XmlException(QObject::tr("Could not create directory %1").arg(
                        newDir.absoluteFilePath(typeName)));
        Q_ASSERT(typeDir.exists());
    }
}

/*!
    \brief Determine the directory for Xml data storage of the given type.
    \details Calculate and return a QDir object for the directory where the
    Xml data items of the \a dirType are located.

    The directory is located under that returned by getDataRootDir().

    If the directory does not exist then this method will attempt to create
    it, and an XmlException() is thrown if this fails.

    \param dirType base type of the data.
    \return QDir value of the Xml data directory for the given type.
    \throw XmlException() if the directory did not exist and could not be
    created.
 */
QDir XmlDirectory::dataDir(XmlPath::BaseTypes dirType) const
{
    QString typeName = XmlPath::BASE_TYPE_NAMES[dirType];
    QDir typeDir(mRootDir.absoluteFilePath(typeName));
    if (!typeDir.exists())
        if (!mRootDir.mkdir(typeName))
            throw XmlException(QObject::tr("Could not create directory %1").arg(
                    mRootDir.absoluteFilePath(typeName)));
    Q_ASSERT(typeDir.exists());
    return typeDir;
}

/*!
    \brief Determine the directory for storage of particular xml data.
    \details Calculate and return a QDir object for the directory where the
    Xml data item or items as dictated by the XmlPath object \a xp.

    \code
    // returns a QDir on <dataroot>/Class/Monk.Trait
    XmlPath xp(DndData::CLASS_BASE, "Monk");
    xp.setSubType(DndData::TRAIT_TYPE);
    QDir monkTraits = XmlDirectory::getDataDir(xp);
    \endcode

    The directory is located under that returned by getDataDir(\a dirType).

    If the directory does not exist then this method will attempt to create
    it, and an XmlException() is thrown if this fails.

    \param xp path of the data.
    \return QDir value of the Xml data directory for the given types.
    \throw XmlException() if the directory did not exist and could not be
    created.
 */
QDir XmlDirectory::dataSubDir(const XmlPath &xp) const
{
    qDebug() << "dataSubDir" << xp.typeName();
    QDir typeDir = dataDir(xp.type());
    if (xp.subType() == XmlPath::NO_TYPE)
        return typeDir;
    QString subTypeName = XmlPath::SUB_TYPE_NAMES[xp.subType()];
    QString pathName = xp.typeName() + "." + subTypeName;
    QDir subDir(typeDir.absoluteFilePath(pathName));
    if (!subDir.exists())
        if (!typeDir.mkdir(pathName))
            throw XmlException(QObject::tr("Could not create sub-directory %1").arg(
                    typeDir.absoluteFilePath(pathName)));
    return subDir;
}
